#include "stdafx.h"
#include "Axis.h"
#include <limits>


// Constructor
_Axis::_Axis(_GraphLayout& Layout):
    m_Layout(Layout)
{
    m_TitleVisible = false;
    m_MaxPrecision = 5;
    m_Max = DBL_MIN;
    m_Min = DBL_MAX;
    m_MaxTicks = 10;
    m_LastMin = 0;
    m_LastMax = 1;
}

// Destructor
_Axis::~_Axis(void)
{
}


/*
*  @brief Calculate the needed precision based on the current tick spacing and exponent
*  @param Current exponent
*/
unsigned int _Axis::getPrecision(int Exponent)
{
    double X = m_TickSpacing / pow(double(10), Exponent);
    return abs(int(log10(abs(X)))) + 1;
}

/*
*  @brief Sets the size of the _Axis
*  @param Size - new size in pixels
*/
void _Axis::setBaseSize(_u32 BaseSize)
{
    m_BaseSize = BaseSize;
}

/*
*  @brief Sets the visibility of the _Axis
*  @param Visible - New visibility
*/
void _Axis::setVisible(bool Visible)
{
    m_Visible = Visible;
}

/*
*  @brief Returns the size of the _Axis
*  @returns Size in pixels
*/
_u32 _Axis::getBaseSize()
{
    return m_BaseSize;
}

/*
*  @brief Returns if the graph is visible or not
*  @returns true or false
*/
bool _Axis::isVisible()
{
    return m_Visible;
}

/*
*  @brief Sets the color of the _Axis
*  @param Color - New _Axis color
*/
void _Axis::setColor(COLORREF Color)
{
    m_Color = Color;
}

/*
*  @brief Returns the color of the _Axis
*  @returns Color as RGB color reference
*/
COLORREF _Axis::getColor()
{
    return m_Color;
}

/*
*  @brief The _Axis string
*  @param Title - String
*/
void _Axis::setTitle(CStringW Title)
{
    m_Title = Title;
}

/*
*  @brief Returns the _Axisstring
*  @returns _Axis as string
*/
CStringW& _Axis::getTitle()
{
    return m_Title;
}

/**
 * Instantiates a new instance of the NiceScale class.
 *
 * @param min the minimum data point on the axis
 * @param max the maximum data point on the axis
 */
void _Axis::NiceScale(double min, double max)
{
    m_Min = min;
    m_Max = max;
    calculateTicks();
}

/**
 * Calculate and update values for tick spacing and nice
 * minimum and maximum data points on the axis.
 */
void _Axis::calculateTicks()
{
    m_Range = niceNum(m_Max - m_Min, false);
    m_TickSpacing = niceNum(m_Range / (m_MaxTicks - 1), true);
    m_NiceMin =
        floor(m_Min / m_TickSpacing) * m_TickSpacing;
    m_NiceMax =
        ceil(m_Max / m_TickSpacing) * m_TickSpacing;
}

/**
 * Returns a "nice" number approximately equal to m_Range Rounds
 * the number if round = true Takes the ceiling if round = false.
 *
 * @param m_Range the data m_Range
 * @param round whether to round the result
 * @return a "nice" number to be used for the data m_Range
 */
double _Axis::niceNum(double m_Range, bool round)
{
    double exponent; /** exponent of m_Range */
    double fraction; /** fractional part of m_Range */
    double niceFraction; /** nice, rounded fraction */
    exponent = floor(log10(m_Range));
    fraction = m_Range / pow(10, exponent);

    if(round)
    {
        if(fraction < 1.5)
        {
            niceFraction = 1;
        }
        else if(fraction < 3)
        {
            niceFraction = 2;
        }
        else if(fraction < 7)
        {
            niceFraction = 5;
        }
        else
        {
            niceFraction = 10;
        }
    }
    else
    {
        if(fraction <= 1)
        {
            niceFraction = 1;
        }
        else if(fraction <= 2)
        {
            niceFraction = 2;
        }
        else if(fraction <= 5)
        {
            niceFraction = 5;
        }
        else
        {
            niceFraction = 10;
        }
    }

    return niceFraction * pow(10, exponent);
}

/**
 * Sets maximum number of tick marks we're comfortable with
 *
 * @param m_MaxTicks the maximum number of tick marks for the axis
 */
void _Axis::setMaxTicks(unsigned int maxTicks1)
{
    m_MaxTicks = maxTicks1;
    calculateTicks();
}


/*
*  @brief Sets the visibility of the axis title
*  @param Visible - New visibility
*/
void _Axis::setTitleVisible(bool Visible)
{
    m_TitleVisible = Visible;
}

/*
*  @brief Returns if the axis-title is visible or not
*  @returns true or false
*/
bool _Axis::isTitleVisible()
{
    return m_TitleVisible;
}

_s32 _Axis::getExponent(double Min, double Max)
{
    _s32 Exponent = 0;

    if(Min != 0 && Max != 0)
    {
        _s32 Exponent1 = (_s32) log10(abs(Min));
        _s32 Exponent2 = (_s32) log10(abs(Max));
        Exponent = max(Exponent1, Exponent2);
    }
    else if(Max == 0 && Min != 0)
    {
        Exponent = (_s32) log10(abs(Min));
    }
    else if(Min == 0 && Max != 0)
    {
        Exponent = (_s32) log10(abs(Max));
    }

    return Exponent;
}

/**
*  @Sets the minimum and maximum of the axis
*
*  @param Min - Minimum
*  @param Max - Maximum
*/
void _Axis::setMinMax(double Min, double Max)
{
    m_Min = Min;
    m_Max = Max;
}


double _Axis::getScaledCoordinate(_u32 Tick)
{
    _u32 NumTicks = (_u32)(m_Range / m_TickSpacing);
    return -1E30 + 1E30 / (Tick / 2 / NumTicks);
}